package com.gitee.wsl.text.template

/*import com.gitee.wsl.base.CharMatcher
import com.gitee.wsl.base.Preconditions.checkArgument
import com.gitee.wsl.text.Substring
import com.gitee.wsl.transform.converter.ConverterSup
import com.gitee.wsl.text.Substring.prefix
import com.gitee.wsl.text.Substring.suffix*/



/**
 * Facade class to generate queries based on a string template in the syntax of [ ], with compile-time guard rails and runtime protection against SQL injection and
 * programmer mistakes. Special characters of string expressions are automatically escaped to
 * prevent SQL injection errors.
 *
 *
 * A SafeQuery encapsulates the query string. You can use [.toString] to access the query
 * string.
 *
 *
 * In addition, a SafeQuery may represent a subquery, and can be passed through [ ][StringFormat.To.with] to compose larger queries.
 *
 *
 * This class is Android compatible.
 *
 * @since 7.0
 */

/*
class SafeQuery(private val query: String) {
    */
/** Returns the encapsulated SQL query.  *//*

    override fun toString(): String {
        return query
    }

    override fun equals(obj: Any?): Boolean {
        return if (obj is SafeQuery) {
            (query == obj.query)
        } else false
    }

    override fun hashCode(): Int {
        return query.hashCode()
    }

    companion object {
        private val ILLEGAL_IDENTIFIER_CHARS: CharMatcher = CharMatcher.anyOf("'\"`()[]{}\\~!@$^*,/?;").or(CharMatcher.javaIsoControl())
        private val TRUSTED_SQL_TYPE_NAME: String = "com.google.storage.googlesql.safesql.TrustedSqlString"
            */
/*firstNonNull<String>(
                System.getProperty("com.google.mu.safesql.SafeQuery.trusted_sql_type"),
                "com.google.storage.googlesql.safesql.TrustedSqlString"
            )*//*


        */
/** Returns a query using a string constant.  *//*

        fun of( query: String): SafeQuery {
            return SafeQuery(query)
        }

        */
/**
         * Returns a collector that can join [SafeQuery] objects using `delim` as the
         * delimiter.
         *//*

       */
/* fun <F> joining( delim: String): Collector<SafeQuery, F, SafeQuery> {

            return Collectors.collectingAndThen(
                Collectors.mapping({ obj: SafeQuery -> obj.toString() }, Collectors.joining(delim))
            ) { query: String ->
                SafeQuery(
                    query
                )
            }
        }*//*


        */
/**
         * Creates a template with the placeholders to be filled by subsequent [ ][StringFormat.To.with] calls. For example:
         *
         * <pre>`private static final StringFormat.To<SafeQuery> FIND_CASE_BY_ID =
         * SafeQuery.template(
         * "SELECT * FROM `{project_id}.{dataset}.Cases` WHERE CaseId = '{case_id}'");
         *
         * // ...
         * SafeQuery query = FIND_CASE_BY_ID.with(projectId, dataset, caseId);
        `</pre> *
         *
         *
         * Placeholders must follow the following rules:
         *
         *
         *  * String placeholder values can only be used when the corresponding placeholder is quoted
         * in the template string (such as '{case_id}').
         *
         *  * If quoted by single quotes (') or double quotes ("), the placeholder value will be
         * auto-escaped.
         *  * If quoted by backticks (`), the placeholder value cannot contain backtick, quotes
         * and other special characters.
         *
         *  * Unquoted placeholders are assumed to be symbols or subqueries. Strings (CharSequence) and
         * characters cannot be used as placeholder value. If you have to pass a string, wrap it
         * inside a [TrustedSqlString] (you can configure the type you trust by setting the
         * "com.google.mu.safesql.SafeQuery.trusted_sql_type" system property).
         *  * An Iterable's elements are auto expanded and joined by a comma and space (", ").
         *  * If the iterable's placeholder is quoted as in `WHERE id IN ('{ids}')`, every
         * expanded element is quoted (and auto-escaped). For example, passing `asList("foo",
         * "bar")` as the value for placeholder `'{ids}'` will result in `WHERE id IN
         * ('foo', 'bar')`.
         *  * If the Iterable's placeholder is backtick-quoted, every expanded element is
         * backtick-quoted. For example, passing `asList("col1", "col2")` as the value for
         * placeholder `` `{cols}` `` will result in `` `col`, `col2` ``.
         *  * Subqueries can be composed by using [SafeQuery] as the placeholder value.
         *
         *
         *
         * The placeholder values passed through [StringFormat.To.with] are checked by ErrorProne
         * to ensure the correct number of arguments are passed, and in the expected order.
         *
         *
         * Supported expression types:
         *
         *
         *  * null (NULL)
         *  * Boolean
         *  * Numeric
         *  * Enum
         *  * String (must be quoted in the template)
         *  * [TrustedSqlString]
         *  * [SafeQuery]
         *  * Iterable
         *
         *//*

        fun template(formatString: String): StringFormat.To<SafeQuery> {
            return template(
                formatString) {
                throw IllegalArgumentException("Unsupported argument type: $it")
                }
        }

        fun template(
            formatString: String,
            defaultConverter: ConverterSup<Any, String>
        ): StringFormat.To<SafeQuery> {
            return StringFormat.template(
                formatString
            ) { fragments, placeholders, args ->
                val stringBuilder = StringBuilder()
                fragments.forEachIndexed { index, s ->
                    stringBuilder
                        .append(s)
                        .append(
                            fillInPlaceholder(
                                placeholders[index],
                                args[index],
                                defaultConverter
                            )
                        )
                }
                SafeQuery(stringBuilder.toString())
                */
/*
                 val it: Iterator<String> = fragments.iterator()
                SafeQuery(
                     placeholders
                         .collect(
                             StringBuilder()
                         ) { b, p, v ->
                             b.append(it.next())
                                 .append(fillInPlaceholder(p, v, defaultConverter))
                         }
                         .append(it.next())
                         .toString())*//*

            }
        }

        private fun fillInPlaceholder(
            placeholder: Substring.SubPatternMatch, value: Any, defaultConverter: ConverterSup<Any, String>
        ): String {
            validatePlaceholder(placeholder)
            if (value is Iterator<*>) {
                */
/*val iterable = value
                if (placeholder.isImmediatelyBetween("`", "`")) { // If backquoted, it's a list of symbols
                    return Iterables.transform(iterable ) { v: Any ->
                            backquoted(placeholder, v)
                        }.join("`, `")
                }
                if (placeholder.isImmediatelyBetween("'", "'")) {
                    return Iterables.transform(iterable) { v: Any ->
                            quotedBy('\'', placeholder, v)
                        }.join("', '")
                }
                return if (placeholder.isImmediatelyBetween("\"", "\"")) {
                    Iterables.transform(iterable) { v: Any ->
                            quotedBy(
                                '"',
                                placeholder,
                                v
                            )
                        }.join("\", \"")
                } else
                    Iterables.transform(iterable) { v: Any? ->
                        unquoted(
                            placeholder,
                            v,
                            defaultConverter
                        )
                    }.join(", ")*//*


                if (placeholder.isImmediatelyBetween("`", "`")) { // If backquoted, it's a list of symbols
                    return value.asSequence().map {
                        if (it != null) {
                            backquoted(placeholder, it)
                        }
                    }.joinToString("`, `")
                }
                if (placeholder.isImmediatelyBetween("'", "'")) {
                    return value.asSequence().map {
                        if (it != null) {
                            quotedBy('\'', placeholder, it)
                        }
                    }.joinToString("`, `")

                }
                return if (placeholder.isImmediatelyBetween("\"", "\"")) {
                   value.asSequence().map {
                        if (it != null) {
                            quotedBy('"', placeholder, it)
                        }
                    }.joinToString("\", \"")
                } else
                    value.asSequence().map {
                        if (it != null) {
                            unquoted(placeholder, it, defaultConverter)
                        }
                    }.joinToString(", ")
            }
            if (placeholder.isImmediatelyBetween("'", "'")) {
                return quotedBy('\'', placeholder, value)
            }
            if (placeholder.isImmediatelyBetween("\"", "\"")) {
                return quotedBy('"', placeholder, value)
            }
            return if (placeholder.isImmediatelyBetween("`", "`")) {
                backquoted(placeholder, value)
            } else unquoted(placeholder, value, defaultConverter)
        }

        private fun unquoted(
            placeholder: Substring.SubPatternMatch, value: Any?, byDefault: ConverterSup<Any, String>
        ): String {
            if (value == null) {
                return "NULL"
            }
            if (value is Boolean) {
                return if (value == java.lang.Boolean.TRUE) "TRUE" else "FALSE"
            }
            if (value is Number) {
                return value.toString()
            }
            if (value is Enum<*>) {
                return value.name
            }
            if (isTrusted(value)) {
                return value.toString()
            }
            checkArgument(
                !(value is CharSequence || value is Char),
                "Symbols should be wrapped inside %s;\n"
                        + "subqueries must be wrapped in another SafeQuery object;\n"
                        + "and string literals must be quoted like '%s'",
                TRUSTED_SQL_TYPE_NAME,
                placeholder
            )
            return byDefault.convert(value)
        }


        private fun quotedBy(quoteChar: Char, placeholder: Substring.SubPatternMatch, value: Any): String {
            checkArgument(
                !isTrusted(value),
                "placeholder of type %s should not be quoted: %s%s%s",
                value.javaClass.simpleName,
                quoteChar,
                placeholder,
                quoteChar
            )
            return escapeQuoted(quoteChar, value.toString())
        }

        private fun backquoted(placeholder: Substring.SubPatternMatch, value: Any): String {
            if (value is Enum<*>) {
                return value.name
            }
            val name = removeQuotes('`', value.toString(), '`') // ok if already backquoted
            // Make sure the backquoted string doesn't contain some special chars that may cause trouble.
            checkArgument(
                ILLEGAL_IDENTIFIER_CHARS.matchesNoneOf(name),
                "placeholder value for `%s` (%s) contains illegal character",
                placeholder,
                name
            )
            return escapeQuoted('`', name)
        }

        private fun escapeQuoted(quoteChar: Char, s: String): String {
            val builder = StringBuilder(s.length)
            var i = 0
            while (i < s.length) {
                val codePoint = s.codePointAt(i)
                if (codePoint == quoteChar.code) {
                    builder.append("\\").appendCodePoint(quoteChar.code)
                } else if (codePoint == '\\'.code) {
                    builder.append("\\\\")
                } else if (codePoint in 0x20..0x7e || codePoint == '\t'.code) {
                    // 0x20 is space, \t is tab, keep. 0x7F is DEL control character, escape.
                    // <=0x1f and >=0x7F are ISO control characters.
                    builder.appendCodePoint(codePoint)
                } else if (Character.charCount(codePoint) == 1) {
                    builder.append(String.format("\\u%04X", codePoint))
                } else {
                    val hi = Character.highSurrogate(codePoint)
                    val lo = Character.lowSurrogate(codePoint)
                    builder.append(String.format("\\u%04X\\u%04X", hi.code, lo.code))
                    i++
                }
                i++
            }
            return builder.toString()
        }

        private fun isTrusted(value: Any): Boolean {
            return value is SafeQuery || (value.javaClass.name == TRUSTED_SQL_TYPE_NAME)
        }

        private fun validatePlaceholder(placeholder: Substring.SubPatternMatch) {
            checkArgument(
                !placeholder.isImmediatelyBetween("`", "'"),
                "Incorrectly quoted placeholder: `%s'",
                placeholder
            )
            checkArgument(
                !placeholder.isImmediatelyBetween("'", "`"),
                "Incorrectly quoted placeholder: '%s`",
                placeholder
            )
        }

        private fun removeQuotes(left: Char, s: String, right: Char): String {
            return Substring.between(prefix(left), suffix(right)).from(s).orElse(s)
        }
    }
}
*/

